package com.ideaaedi.shardingdynamictable.config;

import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.creator.DataSourceProperty;
import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator;
import com.baomidou.dynamic.datasource.provider.AbstractDataSourceProvider;
import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.List;
import java.util.Map;


/**
 * 自定义动态数据源
 * <br />
 * 自定义动态数据源，使自定义的数据源即支持dynamic-datasource方式配置的数据源，又支持sharding数据源
 *
 * @author <font size = "20" color = "#3CAA3C"><a href="https://gitee.com/JustryDeng">JustryDeng</a></font> <img src="https://gitee.com/JustryDeng/shared-files/raw/master/JustryDeng/avatar.jpg" />
 * @since 2023-10-13 10:38:11
 */
@Configuration
@AutoConfigureBefore(
        {DynamicDataSourceAutoConfiguration.class,
                SpringBootConfiguration.class})
public class DataSourceConfig {
    
    /**
     * sharding数据源的名称
     * <br />
     * 注：在配置文件中可以通过设置spring.datasource.dynamic.primary为此值，以使sharding数据源为默认的数据源
     */
    private static final String SHARDING_DATASOURCE_NAME = "sharding_ds";
    
    /**
     * 获取动态数据源配置项
     * <p>
     * 这里会根据yml文件的配置自动加载配置，将多个数据源信息放到datasourceMap中
     */
    @Resource
    private DynamicDataSourceProperties dynamicDataSourceProperties;
    
    /**
     * 获取到sharding的逻辑总数据源
     * <br />
     * 加@Lazy，避免启动时循环依赖报错
     */
    @Lazy
    @Resource(name = "shardingSphereDataSource")
    private DataSource shardingSphereDataSource;
    
    /**
     * 使自定义的数据源即支持dynamic-datasource方式配置的数据源，又支持sharding数据源
     */
    @Bean
    public DynamicDataSourceProvider dynamicDataSourceProvider(@Autowired DefaultDataSourceCreator defaultDataSourceCreator) {
        Map<String, DataSourceProperty> datasourceMap = dynamicDataSourceProperties.getDatasource();
        return new AbstractDataSourceProvider(defaultDataSourceCreator) {
            @Override
            public Map<String, DataSource> loadDataSources() {
                Map<String, DataSource> dataSourceMap = createDataSourceMap(datasourceMap);
                // 将 sharding-jdbc 管理的数据源也交给动态数据源管理
                dataSourceMap.put(SHARDING_DATASOURCE_NAME, shardingSphereDataSource);
                return dataSourceMap;
            }
        };
    }
    
    /**
     * 将此动态数据源设置为首选
     */
    @Bean
    @Primary
    public DataSource dataSource(@Autowired List<DynamicDataSourceProvider> dynamicDataSourceProviders) {
        DynamicRoutingDataSource dynamicRoutingDataSource = new DynamicRoutingDataSource(dynamicDataSourceProviders);
        dynamicRoutingDataSource.setPrimary(dynamicDataSourceProperties.getPrimary());
        dynamicRoutingDataSource.setStrict(dynamicDataSourceProperties.getStrict());
        dynamicRoutingDataSource.setStrategy(dynamicDataSourceProperties.getStrategy());
        dynamicRoutingDataSource.setGraceDestroy(dynamicDataSourceProperties.getGraceDestroy());
        dynamicRoutingDataSource.setP6spy(dynamicDataSourceProperties.getP6spy());
        dynamicRoutingDataSource.setSeata(dynamicDataSourceProperties.getSeata());
        return dynamicRoutingDataSource;
    }
}